Author

Lucas Luo

Published

April 24, 2025

Modified

May 1, 2025

3  Programming Interactive Data Visualisation with R

3.1 Learning Outcome

The following content is created by following the tutorial on this chapter.

3.2 Getting Started

  • ggiraph for making ‘ggplot’ graphics interactive.

  • plotly, R library for plotting interactive statistical graphs.

  • DT provides an R interface to the JavaScript library DataTables that create interactive table on html page.

  • tidyverse, a family of modern R packages specially designed to support data science, analysis and communication task including creating static statistical graphs.

  • patchwork for combining multiple ggplot2 graphs into one figure.

Code
pacman::p_load(ggiraph, plotly, 
               patchwork, DT, tidyverse) 

3.3 Importing Data

Code
exam_data <- read_csv("data/Exam_data.csv")

3.4 Interactive Data Visualisation - ggiraph methods

3.4.1 Tooltip effect with tooltip aesthetic

By hovering the mouse pointer on an data point of interest, the student’s ID will be displayed.

Code
# Step 1: an interactive version of ggplot2 geom (i.e. geom_dotplot_interactive()) will be used to create the basic graph.

p <- ggplot(data = exam_data,
            aes(x = MATHS)) +
  geom_dotplot_interactive(
    aes(tooltip = ID),  # Here's the tooltip
    stackgroups = TRUE,
    binwidth = 1,
    method = "histodot") +
  scale_y_continuous(NULL,
                     breaks = NULL)

# Step 2: Girafe() will be used to generate an svg object to be displayed on an html page.
girafe(
  ggobj = p,
  width_svg = 6,
  height_svg = 6*0.618
)

By hovering the mouse pointer on an data point of interest, the student’s ID will be displayed.

Code
# Step 1: Creating a new column in the dataset to incorporate the tool tip information
exam_data$tooltip <- c(paste0(
  "Name = ", exam_data$ID,
  "\n Class = ", exam_data$CLASS
))

# Step 2: Create an interactive version of ggplot2 geom.
p <- ggplot(data = exam_data,
            aes(x = MATHS)) +
  geom_dotplot_interactive(
    aes(tooltip = exam_data$tooltip),  # Here's the tooltip
    stackgroups = TRUE,
    binwidth = 1,
    method = "histodot") +
  scale_y_continuous(NULL,
                     breaks = NULL)

# Step 3: Generate an svg object to be displayed on an html page.
girafe(
  ggobj = p,
  width_svg = 6,
  height_svg = 6*0.618
)

This changes the tooltip from a black background + white text to a white background + black, bold text.

Code
# Step 1: Define tooltip CSS style
tooltip_css <- "background-color:white;
font-style:bold; color:black;"

# Step 2: Create an interactive version of ggplot2 geom.
p <- ggplot(data = exam_data,
            aes(x = MATHS)) +
  geom_dotplot_interactive(
    aes(tooltip = ID),  # Here's the tooltip
    stackgroups = TRUE,
    binwidth = 1,
    method = "histodot") +
  scale_y_continuous(NULL,
                     breaks = NULL)

# Step 3: Generate an svg object to be displayed on an html page.
girafe(
  ggobj = p,
  width_svg = 6,
  height_svg = 6*0.618,
  options = list(  
    opts_tooltip(
      css = tooltip_css  # The tooltip css is incorporated here
    )
  )
)

Code chunk below shows an advanced way to customise tooltip. In this example, a function is used to compute 90% confident interval of the mean. The derived statistics are then displayed in the tooltip.

Code
tooltip <- function(y, ymax, accuracy = .01) {
  mean <- scales::number(y, accuracy = accuracy)
  sem <- scales::number(ymax - y, accuracy = accuracy)
  paste("Mean maths scores:", mean, "+/-", sem)
}

gg_point <- ggplot(data=exam_data, 
                   aes(x = RACE),
) +
  stat_summary(aes(y = MATHS, 
                   tooltip = after_stat(  
                     tooltip(y, ymax))),  
    fun.data = "mean_se", 
    geom = GeomInteractiveCol,  
    fill = "light blue"
  ) +
  stat_summary(aes(y = MATHS),
    fun.data = mean_se,
    geom = "errorbar", width = 0.2, size = 0.2
  )

girafe(ggobj = gg_point,
       width_svg = 8,
       height_svg = 8*0.618)

3.4.2 Hover effect with data_id aesthetic

Elements associated with a data_id (i.e CLASS) will be highlighted upon mouse over.

Code
p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(           
    aes(data_id = CLASS),             
    stackgroups = TRUE,               
    binwidth = 1,                        
    method = "histodot") +               
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(                                  
  ggobj = p,                             
  width_svg = 6,                         
  height_svg = 6*0.618                      
)                                        

Css codes are used to change the highlighting effect.

Code
p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(data_id = CLASS),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +               
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(                                  
  ggobj = p,                             
  width_svg = 6,                         
  height_svg = 6*0.618,
  options = list(                        
    opts_hover(css = "fill: #202020;"),  
    opts_hover_inv(css = "opacity:0.2;") 
  )                                        
)                                                                         

3.4.3 Combining tooltip and hover effect

The code chunk below combines what we have learnt so far - the tooltip + hover effect.

Code
p <- ggplot(data = exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(tooltip = CLASS, 
        data_id = CLASS),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +               
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(                                  
  ggobj = p,                             
  width_svg = 6,                         
  height_svg = 6*0.618,
  options = list(                        
    opts_hover(css = "fill: #202020;"),  
    opts_hover_inv(css = "opacity:0.2;") 
  )                                        
)            

3.4.4 Customising Tooltip style

onclick argument of ggiraph provides hotlink interactivity on the web. Interactivity: Web document link with a data object will be displayed on the web browser upon mouse click.

Code
exam_data$onclick <- sprintf("window.open(\"%s%s\")",
"https://www.moe.gov.sg/schoolfinder?journey=Primary%20school",
as.character(exam_data$ID))

p <- ggplot(data = exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(onclick = onclick),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +               
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(                                  
  ggobj = p,                             
  width_svg = 6,                         
  height_svg = 6*0.618)                                   

3.4.5 Coordinated multiple views

Coordinated multiple views methods has been implemented in the data visualisation below. Notice that when a data point of one of the dotplot is selected, the corresponding data point ID on the second data visualisation will be highlighted too. The steps will be annotated in the code chunk.

Code
# Step 1: Plot the first figure
p1 <- ggplot(data = exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(data_id = ID,
        tooltip = ID),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +  
  coord_cartesian(xlim = c(0,100)) + 
  scale_y_continuous(NULL,               
                     breaks = NULL)

# Step 2: Plot the second figure
p2 <- ggplot(data = exam_data, 
       aes(x = ENGLISH)) +
  geom_dotplot_interactive(              
    aes(data_id = ID,
        tooltip = ID),        
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") + 
  coord_cartesian(xlim = c(0,100)) + 
  scale_y_continuous(NULL,               
                     breaks = NULL)

# Step 3: Display the svg object. The code argument runs the patchwork function to create the coordinated multiple views.
girafe(code = print(p1 + p2),  # print is needed for the plot to display
       width_svg = 6,
       height_svg = 3,
       options = list(
         opts_hover(css = "fill: #202020;"),
         opts_hover_inv(css = "opacity:0.2;")
         )
       ) 

3.5 Interactive Data Visualisation - plotly methods!

3.5.1 Creating an interactive scatterplot with plot_ly()

Code
plot_ly(data = exam_data, 
             x = ~MATHS, 
             y = ~ENGLISH)
Code
plot_ly(data = exam_data, 
        x = ~MATHS, 
        y = ~ENGLISH,
        color = ~RACE)

3.5.2 Creating an interactive scatter plot: ggplotly() method

The code chunk below plots an interactive scatter plot by using ggplotly().

Code
p <- ggplot(data=exam_data, 
            aes(x = MATHS,
                y = ENGLISH)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
ggplotly(p)

###3.5.3 Coordinated Multiple Views with plotly The creation of a coordinated linked plot by using plotly involves three steps:

Code
# Step 1: Using highlight_key function from plotly package to indicate the shared data
# This creates an object of class crosstalk::SharedData
d <- highlight_key(exam_data)

# Step 2: Create both the scatterplots
p1 <- ggplot(data = d, 
            aes(x = MATHS,
                y = ENGLISH)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))

p2 <- ggplot(data = d, 
            aes(x = MATHS,
                y = SCIENCE)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))

# Step 3: Using subplot to place them side-by-side
subplot(ggplotly(p1),
        ggplotly(p2))

3.6 Interactive Data Visualisation - crosstalk methods!

Crosstalk is an add-on to the htmlwidgets package. It extends htmlwidgets with a set of classes, functions, and conventions for implementing cross-widget interactions (currently, linked brushing and filtering).

Code
# Step 1: Indicate shared data
d <- highlight_key(exam_data) 

# Step 2: Define the ggplot graphic
p <- ggplot(d, 
            aes(ENGLISH, 
                MATHS)) + 
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))

# Step 3: Using the plotly highlight function
gg <- highlight(ggplotly(p),        
                "plotly_selected")  

# Step 4: Putting HTML elements side by side.
crosstalk::bscols(gg,               
                  DT::datatable(d), 
                  widths = 5)  

4 Programming Animated Statistical Graphics with R

4.1 Practical Takeaways

Gained a clear understanding of how animation is constructed frame-by-frame using subsets of the data.

Learned to use transition_*() functions (like transition_reveal()) to create smooth animations in gganimate.

Understood how to control animation speed and behavior via attributes such as frame_time and easing.

Learned how to combine multiple plot layers (e.g., geom_line, geom_point) with animation to tell a dynamic visual story.

Discovered that while animated graphics may not be time-efficient for exploratory analysis, they are highly effective in presentations for capturing attention and emphasizing trends.

4.2 Getting Started

4.2.1 Loading the R packages

  • plotly, R library for plotting interactive statistical graphs.
    plotly ,用于绘制交互式统计图表的 R 库。

  • gganimate, an ggplot extension for creating animated statistical graphs.
    gganimate ,一个用于创建动画统计图表的 ggplot 扩展。

  • gifski converts video frames to GIF animations using pngquant’s fancy features for efficient cross-frame palettes and temporal dithering. It produces animated GIFs that use thousands of colors per frame.
    gifski 使用 pngquant 的高效跨帧调色板和时间抖动功能,将视频帧转换为 GIF 动画。它生成的 GIF 动画每帧使用数千种颜色。

  • gapminder: An excerpt of the data available at Gapminder.org. We just want to use its country_colors scheme.
    gapminder :摘自 Gapminder.org 的数据。我们只想使用它的 country_colors 方案。

  • tidyverse, a family of modern R packages specially designed to support data science, analysis and communication task including creating static statistical graphs.
    tidyverse 是一系列现代 R 包,专门设计用于支持数据科学、分析和通信任务,包括创建静态统计图。

Code
pacman::p_load(readxl, gifski, gapminder,
               plotly, gganimate, tidyverse)

4.2.2 Importing the data

Code
col <- c("Country", "Continent")
globalPop <- read_xls("data/GlobalPopulation.xls",
                      sheet="Data") %>%
  mutate_each_(funs(factor(.)), col) %>%
  mutate(Year = as.integer(Year))

4.3 Animated Data Visualisation: gganimate methods

Code
ggplot(data = globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', 
       x = '% Aged', 
       y = '% Young') 

Code
ggplot(data = globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', 
       x = '% Aged', 
       y = '% Young') +
  transition_time(Year) +  # Transition through distinct states in time   
  ease_aes('linear')  # Control of easing of aesthetics

4.4 Animated Data Visualisation: plotly

4.3.1 Animated bubble plot with ggplotly() method

Code
gg <- ggplot(data = globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(aes(size = Population,
                 frame = Year),
             alpha = 0.7, 
             show.legend = FALSE) +  # The legend is still displayed
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(x = '% Aged', 
       y = '% Young')

ggplotly(gg)
Code
gg <- ggplot(globalPop, 
       aes(x = Old, 
           y = Young, 
           size = Population, 
           colour = Country)) +
  geom_point(aes(size = Population,
                 frame = Year),
             alpha = 0.7) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(x = '% Aged', 
       y = '% Young') + 
  theme(legend.position='none')

ggplotly(gg)

4.3.2 Animated bubble plot with plot_ly() method

Code
bp <- globalPop %>%
  plot_ly(x = ~Old, 
          y = ~Young, 
          size = ~Population, 
          color = ~Continent,
          sizes = c(2, 100),
          frame = ~Year, 
          text = ~Country, 
          hoverinfo = "text",
          type = 'scatter',
          mode = 'markers') %>%
  layout(showlegend = FALSE)
bp